/* 
 * File:   SockEndPointAsincronico.cpp
 * Author: max
 * 
 * Created on June 1, 2013, 3:06 PM
 */

#include "server_SockEndPointAsincronico.h"
#include "common_MutexScopeLocker.h"
#include "common_Codec.h"
#include <string.h>

using namespace TP;
using namespace TP::Comunicacion::Asincronica;

SockEndPointAsincronico::SockEndPointAsincronico(SockEndPoint* pEndPoint){
    _endPoint = pEndPoint;
}

SockEndPointAsincronico::SockEndPointAsincronico(int &pFileDescriptor, struct sockaddr_in* &pClientAddress){
    _endPoint = new SockEndPoint(pFileDescriptor, pClientAddress);
}

SockEndPointAsincronico::SockEndPointAsincronico(int &pFileDescriptor, struct sockaddr_in* &pClientAddress, const int &pTimeout){
    _endPoint = new SockEndPoint(pFileDescriptor, pClientAddress, pTimeout);
}

SockEndPointAsincronico::~SockEndPointAsincronico(){
    delete _endPoint;
}

void SockEndPointAsincronico::Escribir (const uint8_t* pData, const size_t &pLongitudData) throw (Excepcion&){
    
    // Codifica el mensaje (mediante codec.)
    string* mensaje = new string();
    Codec codec;
    codec.codificar(*mensaje, pData, pLongitudData);
    
    // Agrega el mensaje a la cola de densajes entrantes para su posterior envio.
    bufferIn().push(mensaje);

}

void SockEndPointAsincronico::Leer (uint8_t* &pData, uint32_t &pLongitudData) throw (Excepcion&){

    if (bufferOut().size() > 0)
    {
        // Se extrae el primer mensaje de la cola. Se lo decodifica y se lo ubica en pMensaje.
        Codec codec;
        string aux = *(bufferOut().front());
        codec.decodificar(pData, pLongitudData, aux);

        // Desencola el mensaje de la cola y lo elimina.
        delete bufferOut().front();
        bufferOut().pop();
    }
    else
    {
        pData = NULL;
        pLongitudData = 0;
    }
}

void SockEndPointAsincronico::Iniciar() throw (Excepcion&){
    try
    {
        _transmitiendo = true;
        Thread::Iniciar();
    }
    catch (Excepcion &ex)
    {
        throw;
    }
}

void SockEndPointAsincronico::Finalizar() throw (Excepcion&){
    try
    {
        _transmitiendo = false;
        _endPoint->Finalizar();
        
        Thread::Finalizar();
    }
    catch (Excepcion &ex)
    {
        throw;
    }
}

void SockEndPointAsincronico::tarea (){
    
    while (_transmitiendo)
    {
        try
        {
            // Se lee un menesaje desde el socket y se lo encola en la cola de mensajes saliente.
            
            // Levanto el mensaje en memoria.
            uint8_t* data = NULL;
            size_t longitudData = 0;
            _endPoint->Leer(data, longitudData);

            // Vuelco el mensaje en un string para su almacenamiento.
            string* mensaje = new string();
            for (size_t i = 0; i < longitudData; i++)
            {
                *mensaje += data [i];
            }
            delete [] data;
            
            // Encolo el mensaje.
            if (strcmp ("KAKAKA", mensaje->c_str()) != 0)
            {
                bufferOut().push(mensaje);
            }
            
            // Se toma un mensaje de la cola de mensaje a enviar y se lo envia por el socket.
            if (!bufferIn().empty())
            {
                _endPoint->Escribir(reinterpret_cast <const uint8_t*> (bufferIn().front()->c_str()), bufferIn().front()->length());
                delete bufferIn().front();
                bufferIn().pop();
            }
            else
            {
                _endPoint->Escribir(reinterpret_cast <const uint8_t*> ("KAKAKA"), 6);
            }
        }
        catch (Excepcion &ex)
        {
            cerr << ex.what() << endl;
            _transmitiendo = false;
        }
    }
}

queue<string*>& SockEndPointAsincronico::bufferIn(){
    MutexScopeLocker locker (_mutexBufferIn);
    return _bufferIn;
}

queue<string*>& SockEndPointAsincronico::bufferOut(){
    MutexScopeLocker locker (_mutexBufferOut);
    return _bufferOut;
}
